# -*-coding: Utf-8 -*-
# @File : day03 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time：2023/9/29
from fastapi import APIRouter, Path, Query, Cookie, Header
from typing import List

app03 = APIRouter()


# 路径参数和数字验证

# 函数的顺序就是路由访问的顺序
@app03.get('/path/parameters')
def path_params01(parameters: str):
    return {"message": parameters}


# 不带参数的验证
@app03.get('/path/parameters')
def path_params01():
    return {"message": 'This is a message!'}


from enum import Enum


class CityName(str, Enum):
    Beijing = 'Beijing China'
    Shanghai = 'Shanghai China'


# 枚举类型参数
@app03.get('/enum/{city}')
async def lastest(city: CityName):
    if city == CityName.Beijing:
        return {'city_name': city, "confirmed": 1500, "death": 60}
    elif city == CityName.Shanghai:
        return {'city_name': city, "confirmed": 600, 'death': 88}
    else:
        return {'city_name': city, "confirmed": 'unknown'}


# 文件类型
# file_path:path : 当路径中 有 类似于 路由中的 / 时 ，会被解析成字符串类型
@app03.get('/files/{file_path:path}')
async def file_path(file_path: str):
    return f'The file path is {file_path}'


# 路径参数
# from fastapi import Path
# Path 类就是用来校验路径参数用的
@app03.get('/path_num/{num}')
async def path_params_validate(
        # num 必须是 int 类型 ，且 使用 Path 校验 ，必须大于等于1 小于等于10
        # title 给参数 添加标题
        # description ： 给参数 添加描述
        num: int = Path(None, title="Your number", description="校验的数字类型", ge=1, le=10)
):
    return num


from typing import Optional


#####  查询参数和数据的解析与验证

# 模拟分页功能
@app03.get('/query')
# Optional 选填参数，默认 指定 为 None
async def page_limit(page: int = 1, limit: Optional[int] = None):
    if limit:
        return {"page": page, 'limit': limit}
    else:
        return {"page": page}


# 验证布尔类型自动转换
@app03.get('/query/bool/conversion')
async def type_conversion(param: bool = False):
    return param


# 路径参数(字符串类型)验证
# 路径参数 --- 查询参数类型
# from fastapi import Query
# Path 类就是用来校验路径参数用的
@app03.get('/query/validations')
async def query_validations(
        # str 字符串类型
        # ... 必填参数
        # min_length 最小长度
        # max_length 最大长度
        # regex 正则表达式匹配
        value: str = Query(..., min_length=3, max_length=16, regex="^a"),
        # List 列表类型
        # default 默认值
        # alias 参数别名
        values: List[str] = Query(default=['v1', 'v2'], alias="alias_name")
):
    return value, values


# """Request Body + Path parameters + Query parameters 多参数混合"""


from pydantic import BaseModel, Field


## 请求体字段
class CityInfo(BaseModel):
    # 给 name 字段添加注解
    # ... : 表示必填字段
    # example ：表示示例，，只是注解，不会被验证
    name: str = Field(..., example='Beijing')
    country: str
    country_code: str = None
    # 给 country_population 字段进行校验
    # default : 默认值
    # title ： 字段标题
    # description ： 字段描述
    # ge ：大于等于
    country_population: int = Field(default=800, title="人口数量", description="国家人口数量", ge=800)

    # 指定配置
    class Config:
        schema_extra = {
            # 指定默认示例
            "example": {
                "name": "Shanghai",
                "country": "China",
                "country_code": "CN",
                "country_population": 1400000000
            }
        }


@app03.post('/request_body/city')
async def city_info(city: CityInfo):
    print(city.name, city.country)
    return city.dict()


# """Request Body + Path parameters + Query parameters 多参数混合"""
@app03.put('/request_body/city/{name}')
async def mix_city_info(
        # 路径参数
        name: str,
        # 请求体 Body 可以定义多个
        city01: CityInfo,
        city02: CityInfo,
        # 对请求参数进行校验，所以使用 Query
        confirmed: int = Query(ge=0, description="确诊数", default=0),
        death: int = Query(ge=0, description="死亡数", default=0)
):
    if name == "Shanghai":
        return {"Shanghai": {"confirmed": confirmed, "death": death}}
    return city01.dict(), city02.dict()


from datetime import date


class Data(BaseModel):
    # 定义数据格式嵌套的请求体
    city: List[CityInfo] = None
    # 额外的数据类型，还有uuid datetime bytes frozenset等
    # 参考：https://fastapi.tiangolo.com/tutorial/extra-data-types/
    date: date
    confirmed: int = Field(ge=0, description="确诊数", default=0)
    deaths: int = Field(ge=0, description="死亡数", default=0)
    recovered: int = Field(ge=0, description="痊愈数", default=0)


@app03.put('/request_body/nested')
async def nested_models(data: Data):
    return data


## Cookie 和 Header 参数
# 因为 cookie 是浏览器的操作，所以只能用 接口测试工具测试，不能用fastapi自带的文档
@app03.get('/cookie')
async def cookie(cookie_id: Optional[str] = Cookie(None)):
    return {"cookie_id": cookie_id}


@app03.get('/header')
# convert_underscores 是否转换下划线  (user_agent --> user-agent)
async def header(user_agent: Optional[str] = Header(None, convert_underscores=True),
                 x_token: Optional[str] = Header(None)):
    """
    有些HTTP代理和服务器是不允许在请求头中带有下划线的，所以Header提供convert_underscores属性让设置
    :param user_agent: convert_underscores=True 会把 user_agent 变成 user-agent
    :param x_token: x_token是包含多个值的列表
    :return:
    """
    return {"user_agent": user_agent, 'x_token': x_token}
